package view;

import actor.Monster;
import actor.Player;
import round.RoundCount;

import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;

public class GameGround extends JFrame {
    private Monster[] monsters;
    private Player[] players;
    private ActorView[] monsterList = new ActorView[4];
    private ActorView[] playerList = new ActorView[4];
    private final int WIDTH = 1100;
    private final int HEIGHT = 600;
    /*
        0:Init
        1:playerAttack;
        2:playerHeal;
        3:playerPower;
        4:monsterAttack;
     */
    private int operateState = 0;
    private int nowRouter = 0;
    private RoundCount roundCount = new RoundCount();
    private int[] rounds;
    JPanel roundPanel;
    JPanel detailPanel;
    JPanel centerPanel;
    JPanel operatePanel;
    CardLayout operateCard;
    int monsterNum;
    int playerNum;
    int nowRound = 0;
    int detailNum = 0;

    private static final GameGround instance = new GameGround();

    public static GameGround getInstance() {
        return instance;
    }

    public GameGround init(Monster[] monsters, Player[] players) {
        setTitle("MonsterMayhem");
        this.monsters = monsters;
        this.players = players;

        for (int i = 0; i < 4; i++) {
            if (monsters[i] == null) {
                break;
            }
            monsterNum++;
        }
        for (int i = 0; i < 4; i++) {
            if (players[i] == null) {
                break;
            }
            playerNum++;
        }
        JPanel topPanel = new JPanel();
        topPanel.add(new JLabel("Round " + nowRound));
        roundPanel = creatRoundPanel();
        detailPanel = createDetailPanel();
        operatePanel = createOperatePanel();

        operateCard = (CardLayout) operatePanel.getLayout();

        centerPanel = createCenterPanel();

        add(topPanel, BorderLayout.NORTH);
        add(centerPanel, BorderLayout.CENTER);
        add(detailPanel, BorderLayout.EAST);
        add(roundPanel, BorderLayout.WEST);
        add(operatePanel, BorderLayout.SOUTH);

        setTitle("GameGround");
        setSize(WIDTH, HEIGHT);
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        initRound();
        setVisible(true);
        return instance;
    }

    private GameGround() {

    }

    private JPanel createOperatePanel() {
        JPanel operatePanel = new JPanel(new CardLayout());
        JPanel monsterOperatePanel = new JPanel();
        JPanel playerOperatePanel = new JPanel();
        JButton monsterAttack = new JButton("ATTACK");
        monsterAttack.addActionListener(e -> operateState = 4);
        monsterOperatePanel.add(monsterAttack);
        JButton playerAttack = new JButton("ATTACK");
        JButton playerHeal = new JButton("HEAL");
        JButton playerPowerUp = new JButton("POWER-UP");
        playerOperatePanel.add(playerAttack);
        playerOperatePanel.add(playerHeal);
        playerOperatePanel.add(playerPowerUp);
        JLabel loseLabel = new JLabel("YOU DIED!");
        JLabel winLabel = new JLabel("YOU WIN!!");

        operatePanel.add(monsterOperatePanel, "monster");
        operatePanel.add(playerOperatePanel, "player");
        operatePanel.add(loseLabel, "lose");
        operatePanel.add(winLabel, "win");

        playerAttack.addActionListener(e -> operateState = 1);
        playerHeal.addActionListener(e -> operateState = 2);
        playerPowerUp.addActionListener(e -> operateState = 3);

        return operatePanel;
    }

    private JPanel creatRoundPanel() {
        JPanel roundPanel = new JPanel();
        roundPanel.setBorder(new LineBorder(Color.BLACK, 2));
        roundPanel.setLayout(new BoxLayout(roundPanel, BoxLayout.Y_AXIS));
        return roundPanel;
    }

    private JPanel createDetailPanel() {
        JPanel detailPanel = new JPanel();
//        detailPanel.setLayout(new GridLayout(20, 1, 0, 5));
        detailPanel.setBorder(new LineBorder(Color.BLACK, 2));
        detailPanel.setLayout(new BoxLayout(detailPanel, BoxLayout.Y_AXIS));
        JLabel text = new JLabel("RoundStart!!!");
        text.setPreferredSize(new Dimension(150, 20));
        detailPanel.add(text);
        return detailPanel;
    }

    private JPanel createCenterPanel() {
        JPanel centerPanel = new JPanel();
        centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.Y_AXIS));

        JPanel monsterPanel = new JPanel();
        monsterPanel.setLayout(new BoxLayout(monsterPanel, BoxLayout.X_AXIS));
        JPanel playerPanel = new JPanel();
        playerPanel.setLayout(new BoxLayout(playerPanel, BoxLayout.X_AXIS));

        for (int i = 0; i < 4; i++) {
            if (monsters[i] == null) {
                break;
            }
            monsterList[i] = new ActorView(monsters[i], false);
            monsterList[i].setBounds(i * 208, 0, 200, 300);
            int finalI = i;
            monsterList[i].addMouseListener(new MouseAdapter() {
                final int index = finalI;

                @Override
                public void mouseClicked(MouseEvent e) {
                    if (operateState == 1 && monsters[index].isAlive()) {
                        String detailString = "Player:" + players[nowRouter].getName() + " attack:" + monsters[index].getName();
                        addDetail(detailString);
                        detailNum++;
                        SwingUtilities.updateComponentTreeUI(detailPanel);
                        int damaged = players[nowRouter].attack(monsterList[index]);
                        String resultString;
                        if (damaged == -1) {
                            resultString = "miss!";
                        } else {
                            resultString = "damage " + damaged;
                        }
                        addDetail(resultString);
                        if (!monsters[index].isAlive()) {
                            monsterList[index].killed();
                            String killedString = "monster:" + monsters[index].getName() + " has been killed!";
                            addDetail(killedString);
                            monsterNum--;
                            if (monsterNum == 0) {
                                operateCard.show(operatePanel, "win");
                                addDetail("player Wins");
                                return;
                            }
                            flashRound(index + 4);
                        } else
                            nextTurn();
                    }
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    monsterList[index].enter();
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    monsterList[index].exit();
                }
            });
            monsterPanel.add(monsterList[i]);
        }
        for (int i = 0; i < 4; i++) {
            if (players[i] == null) {
                break;
            }
            playerList[i] = new ActorView(players[i], true);
            playerList[i].setBounds(i * 208, 400, 200, 300);
            int finalI = i;
            playerList[i].addMouseListener(new MouseAdapter() {
                final int index = finalI;

                @Override
                public void mouseClicked(MouseEvent e) {
                    if (operateState == 2 && players[index].isAlive()) {
                        System.out.println(index);
                        String detailString = "Player:" + players[nowRouter].getName() + " heal:" + players[index].getName();
                        addDetail(detailString);
                        int hasHealed = players[nowRouter].heal(playerList[index]);
                        String resultString;
                        if (hasHealed == -1) {
                            resultString = "heal failure!";
                        } else {
                            resultString = "heal " + hasHealed;
                        }
                        addDetail(resultString);
                        SwingUtilities.updateComponentTreeUI(detailPanel);
                        nextTurn();
                    } else if (operateState == 3 && players[index].isAlive()) {
                        System.out.println(index);
                        String detailString = "Player:" + players[nowRouter].getName() + " powered:" + players[index].getName();
                        addDetail(detailString);
                        boolean result = players[nowRouter].power(players[index]);
                        String resultString;
                        if (result) {
                            resultString = "powerTo " + players[index].getPower();
                        } else {
                            resultString = "power failure ";
                        }
                        addDetail(resultString);
                        SwingUtilities.updateComponentTreeUI(detailPanel);
                        nextTurn();
                    } else if (operateState == 4 && players[index].isAlive()) {
                        System.out.println(index);
                        String detailString = "Monster:" + monsters[nowRouter - 4].getName() + " attack:" + players[index].getName();
                        addDetail(detailString);
                        int damaged = monsters[nowRouter - 4].attack(playerList[index]);
                        String resultString;
                        if (damaged == -1) {
                            resultString = "miss!";
                        } else {
                            resultString = "damage " + damaged;
                        }
                        addDetail(resultString);
                        if (!players[index].isAlive()) {
                            playerList[index].killed();
                            String killedString = "player:" + players[index].getName() + " has been killed!";
                            addDetail(killedString);
                            playerNum--;
                            if (playerNum == 0) {
                                operateCard.show(operatePanel, "lose");
                                addDetail("player lose");
                                return;
                            }
                            flashRound(index);
                        } else
                            nextTurn();
                    }
                }

                @Override
                public void mouseEntered(MouseEvent e) {
                    playerList[index].enter();
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    playerList[index].exit();
                }
            });
            playerPanel.add(playerList[i]);
        }
        centerPanel.add(monsterPanel);
        centerPanel.add(playerPanel);
        return centerPanel;
    }

    private void nextTurn() {
        int leftTurns = roundCount.getLeftTurns();
        roundPanel.remove(0);

        if (leftTurns == 0) {
            initRound();
            return;
        }
        int nowTurn = roundCount.nextTurn();
        nowRouter = nowTurn;
        System.out.println("2nowRouter:" + nowRouter);
        if (nowTurn < 4) {
            operateCard.show(operatePanel, "player");
        } else {
            operateCard.show(operatePanel, "monster");
        }

    }

    private void initRound() {
        int[] speeds = new int[8];
        for (int i = 0; i < 4; i++) {
            if (players[i] == null)
                break;
            speeds[i] = players[i].getSpeed();
        }
        for (int i = 0; i < 4; i++) {
            if (monsters[i] == null)
                break;
            speeds[i + 4] = monsters[i].getSpeed();
        }
        int firstRound = roundCount.initRound(speeds);
        rounds = roundCount.getRound();

        System.out.println("init:" + Arrays.toString(rounds));
        if (firstRound < 4) {
            roundPanel.add(new RoundTurns(players[firstRound]));
        } else {
            roundPanel.add(new RoundTurns(monsters[firstRound - 4]));
        }

        for (int round : rounds) {
            if (round < 4) {
                roundPanel.add(new RoundTurns(players[round]));
            } else {
                roundPanel.add(new RoundTurns(monsters[round - 4]));
            }
        }
        nowRouter = firstRound;
        if (firstRound < 4) {
            operateCard.show(operatePanel, "player");
        } else {
            operateCard.show(operatePanel, "monster");
        }
    }

    //after someone dies, their round should be removed;
    private void flashRound(int kill) {
        System.out.println("beforeKill " + Arrays.toString(roundCount.getRound()));
        rounds = roundCount.flash(kill);
        System.out.println("kill:" + kill + "--" + Arrays.toString(rounds));
        if (rounds.length == 0) {
            initRound();
        } else {
            roundPanel.removeAll();
            for (int round : rounds) {
                if (round < 4) {
                    roundPanel.add(new RoundTurns(players[round]));
                } else {
                    roundPanel.add(new RoundTurns(monsters[round - 4]));
                }
            }
            int nowTurn = rounds[0];
            nowRouter = nowTurn;
            System.out.println("kill next:" + nowRouter);
            if (nowTurn < 4) {
                operateCard.show(operatePanel, "player");
            } else {
                operateCard.show(operatePanel, "monster");
            }
            roundCount.nextTurn();
            SwingUtilities.updateComponentTreeUI(roundPanel);
        }

    }

    private void addDetail(String detail) {
        JLabel detailLabel = new JLabel(detail);

        if (detailNum > 25) {
            detailPanel.remove(0);
        }
        detailPanel.add(detailLabel);
        detailNum++;
    }

}
